package utils;

import java.awt.image.*;
import java.io.*;
import javax.imageio.*;

/**
 *
 * @author Michał
 */
public class BasicOperations
{

    public static int[] convert3DArrayToPixels(int[][][] data, int noCols, int noRows)
    {
        int[] result = new int[noCols * noRows * 4];

        for (int row = 0, noPixels = 0; row < noRows; row++)
        {
            for (int col = 0; col < noCols; col++)
            {
                result[noPixels] = ((data[row][col][0] << 24) & 0xFF000000) | ((data[row][col][1] << 16) & 0x00FF0000) | ((data[row][col][2] << 8) & 0x0000FF00) | ((data[row][col][3]) & 0x000000FF);
                noPixels++;
            }
        }
        return result;
    }

    public static int[][][] convertPixelsTo3DArray(int[] pixels, int noCols, int noRows)
    {
        int[][][] result = new int[noRows][noCols][4];

        for (int row = 0; row < noRows; row++)
        {
            int[] tmpRow = new int[noCols];
            for (int col = 0; col < noCols; col++)
            {
                int element = row * noCols + col;
                tmpRow[col] = pixels[element];
            }

            for (int col = 0; col < noCols; col++)
            {
                result[row][col][0] = (tmpRow[col] >> 24) & 0xFF; //Alpha   
                result[row][col][1] = (tmpRow[col] >> 16) & 0xFF; //Red
                result[row][col][2] = (tmpRow[col] >> 8) & 0xFF; //Green
                result[row][col][3] = (tmpRow[col]) & 0xFF; //Blue
            }
        }
        return result;
    }

    public static BufferedImage readImage(String path)
    {
        BufferedImage img = null;
        try
        {
            File f = new File(path);
            img = ImageIO.read(f);

        }
        catch (IOException ex)
        {
            System.out.println(ex);
        }
        return img;
    }

    public static boolean writeImage(BufferedImage img, String path, String formatName)
    {
        try
        {
            File f = new File(path);
            ImageIO.write(img, formatName, f);
        }
        catch (IOException ex)
        {
            System.out.println(ex);
            return false;
        }
        return true;
    }

    public static boolean saveChannel(int[] channel, String path, int channelShift)
    {
        boolean result = true;
        FileOutputStream fOut = null;
        ObjectOutputStream oOut = null;

        byte[] toWrite = new byte[channel.length];
        for (int i = 0; i < channel.length; i++)
        {
            toWrite[i] = (byte) ((channel[i] >> channelShift) & 0xFF);
        }
        try
        {
            fOut = new FileOutputStream(path);
            oOut = new ObjectOutputStream(fOut);
            oOut.writeObject(toWrite);
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
            result = false;
        }
        finally
        {
            try
            {
                oOut.flush();
                oOut.close();
                fOut.close();
            }
            catch (IOException ex)
            {
                ex.printStackTrace();
                result = false;
            }
        }
        return result;
    }

    public static int[] loadChannel(String path, int channelShift)
    {
        int[] result = null;
        byte[] dataRead = null;
        FileInputStream fIn = null;
        ObjectInputStream oIn = null;

        try
        {
            fIn = new FileInputStream(path);
            oIn = new ObjectInputStream(fIn);

            dataRead = (byte[]) oIn.readObject();
            result = new int[dataRead.length];
            for (int i = 0; i < dataRead.length; i++)
            {
                result[i] = dataRead[i] << channelShift;
            }
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
        finally
        {
            try
            {
                oIn.close();
                fIn.close();
            }
            catch (IOException ex)
            {
                ex.printStackTrace();
            }
        }
        return result;
    }

    public static BufferedImage filterAll(BufferedImage src, int maskSize) throws Exception
    {
        FullMedianFilter filter = new FullMedianFilter();
        filter.initializeFilter(maskSize);
        BufferedImage result = filter.createCompatibleDestImage(src, null);
        filter.filter(src, result);
        return result;
    }

    public static int[] filterChannel(BufferedImage src, int maskSize, int channelShift) throws Exception
    {
        MonoMedianFilter filter = new MonoMedianFilter();
        filter.initializeFilter(maskSize, channelShift);
        return filter.filter(src);
    }

    public static BufferedImage mergeFilteredChannels(BufferedImage src, int[][] channels)
    {
        MonoMedianFilter filter = new MonoMedianFilter();
        BufferedImage result = filter.createCompatibleDestImage(src, null);

        int[] pixels = filter.mergeChannels(channels);
        filter.setRGB(result, 0, 0, src.getWidth(), src.getHeight(), pixels);

        return result;
    }

    public static BufferedImage medianFilter(BufferedImage src, int maskSize, int noChannels)
    {
        try
        {
            MonoMedianFilter[] filters = new MonoMedianFilter[noChannels];
            int[][] images = new int[noChannels][];
            int channelShift = 0;
            for (int i = 0; i < noChannels; i++)
            {
                filters[i] = new MonoMedianFilter();
                filters[i].initializeFilter(maskSize, channelShift);
                images[i] = filters[i].filter(src);
                channelShift += 8;
            }

            BufferedImage result = filters[0].createCompatibleDestImage(src, null);
            int[] pixels = filters[0].mergeChannels(images);
            filters[0].setRGB(result, 0, 0, src.getWidth(), src.getHeight(), pixels);
            return result;
        }
        catch (Exception ex)
        {
            System.out.println(ex);
        }
        return null;
    }
}
